package YAPserver.behaviours;

import YAPserver.gameObjects.AbstractBall;
import YAPserver.gameObjects.AbstractGameObject;
import YAPserver.gameObjects.Line;
import YAPserver.gameObjects.Point;
import YAPserver.gameObjects.AbstractWall;

/**
 * This class is to be used in combination with the bounce behaviours.
 * The most important methods are listed here.
 * @author Daniel
 *
 */
public class Tool {
	/**
	 * Returns the reflected middle point of a ball off of GameObject (i.e. a wall or a slider)
	 * The middle point is reflected in the line of the GameObject.
	 * The formula for this was found here: http://de.wikipedia.org/wiki/Spiegelungsmatrix
	 * @param ball ballAbstract whose middle point is to be reflected
	 * @param object GameObject whose line is used as the reflection axis
	 * @return the reflected middle point of the ball
	 */
	public static Point reflection(AbstractBall ball, AbstractGameObject object) {
		Line tempLine = object.getLine();
		Line ballLine = ball.getLine();
		
		double objectAngle = tempLine.getAngle();
		
		Point a = tempLine.getStartPoint();
		Point v = ballLine.getStartPoint();
		Point q = v.subtract(a);
		q = reflectOrigin(q, 2*objectAngle);
		q = q.add(a);
		
		return q;
	}
	/**
	 * Returns the point of intersection between a ball (abstract) and another object (typically a slider or wall).
	 * @param ball ballAbstracr that intersects an object
	 * @param object GameObject that has been intersected
	 * @return the point of intersection
	 */
	public static Point intersection(AbstractBall ball, AbstractGameObject object){
		Point objectStart = object.getLine().getStartPoint();
		Point objectEnd = object.getLine().getEndPoint();
		Point ballStart = ball.getLine().getStartPoint();
		Point ballEnd = ball.getLine().getEndPoint();
		if(ball.hasAreaIntersection()){
			Point point = new Point(((AbstractWall) object).getNormal());
			point.scalarMult(-ball.getRadius());
			ballStart = ball.getMiddlePoint();
			ballEnd = ball.getMiddlePoint().add(point);
			ball.setAreaIntersection(false);
		}
		double mObject = (objectStart.getYPos()-objectEnd.getYPos()) / (objectStart.getXPos()-objectEnd.getXPos());
		double mBall = (ballStart.getYPos()-ballEnd.getYPos()) / (ballStart.getXPos()-ballEnd.getXPos());
		
		double cObject = objectStart.getYPos() - mObject*objectStart.getXPos();
		double cBall = ballStart.getYPos() - mBall*ballStart.getXPos();
		
		double x;
		double y;
		if(ballStart.getXPos()-ballEnd.getXPos() == 0){
			x = ballStart.getXPos();
			y = mObject*x + cObject;
		}else if(objectStart.getXPos()-objectEnd.getXPos() == 0){
			x = objectStart.getXPos();
			y = mBall*x + cBall;
		}else{	
			x = (cObject - cBall)/(mBall - mObject);
			y = (cObject*mBall - cBall*mObject)/(mBall - mObject);
		}
		return new Point(x,y);
	}

	/**
	 * Reflects a point in a line through the origin (0,0).
	 * @param point point to be reflected
	 * @param angle double angle of the line
	 * @return reflected point
	 */
	private static Point reflectOrigin(Point point, double angle){
		double x = point.getXPos()*Math.cos(angle)+point.getYPos()*Math.sin(angle);
		double y = point.getXPos()*Math.sin(angle)-point.getYPos()*Math.cos(angle);
		return new Point(x,y);
	}
}
